package tools.genomeMatrix;

import java.io.BufferedWriter;
import java.util.ArrayList;

public class genomeGapSet {

	private genomeGap parent;
	private ArrayList<ArrayList<genomeGap>> strains;
	private final int nrOfStrains;
	private int[] coverage;
	private int size;
	private final String sep="\t";
	
	public genomeGapSet(int nrOfStrains){
		super();
		this.nrOfStrains=nrOfStrains;
		size=0;
		strains= new ArrayList<ArrayList<genomeGap>>();
		coverage= new int[nrOfStrains];
		for(int i=0;i<nrOfStrains;i++){
			strains.add(new ArrayList<genomeGap>());
			coverage[i]=0;
		}
		parent= new genomeGap(-1,0,0);
	}
	
	//assumes non-overlapping genomeGaps...
	public void add(genomeGap gg){
		if(size==0){
			parent.setStart(gg.getStart());
			parent.setEnd(gg.getEnd());
		}
		parent.extend(gg);
		strains.get(gg.getStrain()).add(gg);
		coverage[gg.getStrain()]+=gg.getLength();
		size++;
	}
	
	public void add(ArrayList<genomeGap> ggAL){
		for (genomeGap gg : ggAL) {
			this.add(gg);
		}
	}
	
	public void add(genomeGapSet ggs){
		// could probably be written better
		for (ArrayList<genomeGap> ggAL : ggs.strains) {
			this.add(ggAL);
		}
	}
	
	//recursivly clusters the genomeGaps, demanding a minimum coverage of 90% or all but one if the length is between 1 and 10
	public int cluster(BufferedWriter out,BufferedWriter hard,String chr,int id) throws Exception{
		int idHere=id;
		ArrayList<Integer> done= new ArrayList<Integer>();
		if(parent.getLength()>9){
			//use 90%
			for(int i=0;i<nrOfStrains;i++){
				if((double)coverage[i]/parent.getLength()>0.9){
					done.add(i);
				}
			}
		}else if(parent.getLength()>1){
			//use all but one
			for(int i=0;i<nrOfStrains;i++){
				if(coverage[i]>parent.getLength()-2){
					done.add(i);
				}
			}
		}else{
			//the length is one and one must be present
			for(int i=0;i<nrOfStrains;i++){
				if(coverage[i]==1){
					done.add(i);
				}
			}
		}
		if(done.size()==0){
			//print to the hard clusters file
			String label=idHere+"";
			while(label.length()<12){
				label="0"+label;
			}
			label="G"+label;
			idHere++;
			hard.write(label+sep+chr+sep+parent.getStart()+sep+parent.getEnd());
			for(int i=0;i<nrOfStrains;i++){
				hard.write(sep+coverage[i]);
			}
			hard.write("\n");
		}else{
			//print and find new clusters
			String label=idHere+"";
			while(label.length()<12){
				label="0"+label;
			}
			label="G"+label;
			idHere++;
			out.write(label+sep+chr+sep+parent.getStart()+sep+parent.getEnd());
			ArrayList<genomeGap> toReCluster= new ArrayList<genomeGap>();
			for(int i=0;i<nrOfStrains;i++){
				if(done.contains(i)){
					out.write(sep+"1");
				}else{
					out.write(sep+"0");
					for(genomeGap e: strains.get(i)){
						toReCluster.add(e);
					}
				}
			}
			out.write("\n");
			//recluster
			for (genomeGapSet ggs : this.recluster(toReCluster)) {
				idHere=ggs.cluster(out, hard, chr, idHere);
			}
		}
		
		return idHere;
	}
	
	
	private ArrayList<genomeGapSet> recluster(ArrayList<genomeGap> toReCluster){
		ArrayList<genomeGapSet> reclustered= new ArrayList<genomeGapSet>();
		ArrayList<Integer> Overlap;
		for (genomeGap gg : toReCluster) {
			Overlap= new ArrayList<Integer>();
			for(int i=0;i<reclustered.size();i++){
				if(reclustered.get(i).overlap(gg)){
					Overlap.add(i);
				}
			}
			if(Overlap.size()==0){
				//create new genomeGapSet
				genomeGapSet tmp= new genomeGapSet(nrOfStrains);
				tmp.add(gg);
				reclustered.add(tmp);
			}else if(Overlap.size()==1){
				//Add the genomeGap to the correct genomeGapSet
				reclustered.get(Overlap.get(0)).add(gg);
			}else{
				//merge genomeGapSets
				genomeGapSet parent= reclustered.get(Overlap.get(0));
				for (int i=Overlap.size()-1;i>0;i--) {
					parent.add(reclustered.remove((int)Overlap.get(i)));
				}
			}
		}
		return reclustered;
	}
	
	public boolean overlap(genomeGap gg){
		return this.parent.overlap(gg);
	}
}
